fix(integrations): dispatch bob commands via bob run - #4492
Conversation
`BobIntegration` never overrode `build_exec_args()`, so it inherited the `IntegrationBase` no-op returning `None`. Callers read `None` as "this CLI is unavailable", so every workflow command/prompt step targeting Bob reported `CLI not found or not installed` even with `bob` on PATH. `build_command_invocation()` was inherited too, rendering `/speckit.specify` where skills-mode projects install `.bob/skills/speckit-specify/`.
There was a problem hiding this comment.
🟡 Changes recommended
Legacy-mode and dotted extension commands currently produce incorrect invocations.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Enables Bob workflow dispatch through its headless bob run interface.
Changes:
- Adds Bob CLI argument and command-invocation construction.
- Adds regression tests for dispatch formats and IDE-first configuration.
File summaries
| File | Description |
|---|---|
src/specify_cli/integrations/bob/__init__.py |
Implements Bob headless dispatch. |
tests/integrations/test_integration_bob.py |
Tests Bob dispatch behavior. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Thanks — the |
…dispatched into
`build_command_invocation()` called `effective_invoke_separator()` with no
arguments, so `is_skills_mode()` never reached its disk-detection branch
(bob/__init__.py:223-228) and always returned the fresh-project default.
`dispatch_command()` does receive the workflow project root, but the shared
two-argument `build_command_invocation(command_name, args)` contract -- which
eight integrations implement -- had nowhere to put it.
Two consequences, measured against a real `.bob/commands/speckit.specify.md`
project:
legacy project, speckit.specify -> /speckit-specify (want /speckit.specify)
skills project, speckit.git.commit -> /speckit-git.commit (want /speckit-git-commit)
(a) Every existing Bob 1.x install is dispatched a skills-mode invocation
naming a command it does not have, so the run fails exactly as it did before
dispatch was implemented.
(b) Only the `speckit.` prefix was converted, leaving inner dots. The
installed skill directory is `speckit-git-commit` -- `SkillsIntegration`
derives it with `stem.replace(".", "-")` (base.py:1759) and renders the
invocation the same way (base.py:1649) -- so a dotted extension command names
a skill that does not exist. The two layouts differ in both the separator and
the dot handling: skills flatten every dot, legacy commands keep them.
`_build_dispatch_prompt()` carries the project root from `dispatch_command()`
into invocation building. The base implementation is the call it replaces, so
the other integrations are unaffected; Bob overrides it to resolve the layout
from disk, falling back to the working directory, which is where
`dispatch_command` runs `bob` when no root is given.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqDT4qTj3sFBeg9tMRiXqZ
Upstream github#4425 (per-step integration configuration) landed after this branch was pushed and collided with it in two ways. The textual conflict is one region of dispatch_command(): github#4425 inserted a validate_runtime_config() call on the line above the one this branch changed. The two edits are independent, so both survive -- validation first, then _build_dispatch_prompt() builds the prompt. The second collision is semantic and git does not flag it. github#4425 widened build_exec_args() with integration_args/integration_options and updated all fifteen integrations that override it. Bob's override arrives with this branch, so github#4425 had nothing to update, and merging alone would raise TypeError on every Bob dispatch -- the path this branch exists to make work. tests/integrations/test_base.py enumerates the registry and catches it: AssertionError: bob TypeError: BobIntegration.build_exec_args() got an unexpected keyword argument 'integration_args' Bob therefore takes the same four lines as every other integration: the two keyword-only parameters and a validate_runtime_config() call first, copied from CursorAgentIntegration and DroidIntegration. Bob accepts no per-step runtime configuration, so the inherited default -- which rejects non-empty values rather than ignoring them -- is the correct behaviour. Verified: 2915 integration tests pass; the registry test is red without the Bob change and green with it; ruff reports nothing on the three changed files; and dispatch renders /speckit.specify for a legacy project, /speckit-git-commit for a skills project. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqDT4qTj3sFBeg9tMRiXqZ
There was a problem hiding this comment.
🟢 Approval recommended
The reviewed changes have regression coverage and no unresolved blocking issues.
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
|
Thanks @temp-droid — the project-aware dispatch now preserves legacy Bob invocations, and skills-mode extension commands correctly flatten every separator. The runtime-configuration compatibility update is also included. Both requested corrections are addressed, and CI and the follow-up review pass on the current head. No further author changes requested from this pass; this is ready for my final review and merge decision. Drafted for @mnriem by GitHub Copilot (model: GPT-6 Astra). |
|
Thank you! |
* Update Status Report extension to v1.4.2 Update status-report extension submitted by @jwesleye: - extensions/catalog.community.json (version, download_url, effect, requires, etc.) - docs/community/extensions.md community extensions table Closes #4519 Assisted-by: GitHub Copilot (model: gpt-5.2-codex, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: simplify README around three processes (#4591) * docs: simplify README around three processes Use one shared setup and independent SDD, bug-fixing, and idea-assessment quickstarts. Consolidate detailed content into the docs and contributor guide, add missing process guides, align Chinese documentation, and preserve navigation without widening the site header. Assisted-by: GitHub Copilot (model: gpt-6-astra, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs: distinguish agent skills from terminal setup Explicitly describe workflow steps as skills invoked in the agent chat, while reserving terminal instructions for CLI installation and project or extension setup. Assisted-by: GitHub Copilot (model: gpt-6-astra, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Bound speckit.clarify planning deferral to implementation details (#4507) * Gate speckit.clarify so spec-taxonomy items are not deferred to plan The command treated "better deferred to planning" as a catch-all, so agents skipped NFRs, acceptance criteria, and edge cases. Spec hits must stay question candidates. Defer only implementation method, tech-stack comparison, or task breakdown. Fixes #1717 * Bound clarify planning deferral to implementation and tech-stack The unbounded "better deferred to planning" catch-all is gone. Spec taxonomy still lives in the command. Stage-gate procedure and defer-ratio audit belong in an opt-in wrap preset, not core. * Bound the clarify completion-report Deferred status too. The candidate-question skip was already limited to implementation method, tech-stack, or task breakdown. The coverage table still called anything "better suited for planning" Deferred. That leftover catch-all is gone, and the test now covers the report. * fix(integrations): dispatch bob commands via `bob run` (#4492) * fix(integrations): dispatch bob commands via `bob run` `BobIntegration` never overrode `build_exec_args()`, so it inherited the `IntegrationBase` no-op returning `None`. Callers read `None` as "this CLI is unavailable", so every workflow command/prompt step targeting Bob reported `CLI not found or not installed` even with `bob` on PATH. `build_command_invocation()` was inherited too, rendering `/speckit.specify` where skills-mode projects install `.bob/skills/speckit-specify/`. * fix(integrations): resolve the command layout from the project being dispatched into `build_command_invocation()` called `effective_invoke_separator()` with no arguments, so `is_skills_mode()` never reached its disk-detection branch (bob/__init__.py:223-228) and always returned the fresh-project default. `dispatch_command()` does receive the workflow project root, but the shared two-argument `build_command_invocation(command_name, args)` contract -- which eight integrations implement -- had nowhere to put it. Two consequences, measured against a real `.bob/commands/speckit.specify.md` project: legacy project, speckit.specify -> /speckit-specify (want /speckit.specify) skills project, speckit.git.commit -> /speckit-git.commit (want /speckit-git-commit) (a) Every existing Bob 1.x install is dispatched a skills-mode invocation naming a command it does not have, so the run fails exactly as it did before dispatch was implemented. (b) Only the `speckit.` prefix was converted, leaving inner dots. The installed skill directory is `speckit-git-commit` -- `SkillsIntegration` derives it with `stem.replace(".", "-")` (base.py:1759) and renders the invocation the same way (base.py:1649) -- so a dotted extension command names a skill that does not exist. The two layouts differ in both the separator and the dot handling: skills flatten every dot, legacy commands keep them. `_build_dispatch_prompt()` carries the project root from `dispatch_command()` into invocation building. The base implementation is the call it replaces, so the other integrations are unaffected; Bob overrides it to resolve the layout from disk, falling back to the working directory, which is where `dispatch_command` runs `bob` when no root is given. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqDT4qTj3sFBeg9tMRiXqZ --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: release 1.0.7, begin 1.0.8.dev0 development (#4592) * chore: bump version to 1.0.7 * chore: begin 1.0.8.dev0 development --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: upgrade feature-assess to gh-aw v0.88.7 (#4546) * chore: upgrade feature-assess to gh-aw v0.88.7 Regenerate the feature assessment workflow on the current upstream baseline and add positive and negative compatibility checks. Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: assert feature-assess safe output permissions Assisted-by: GitHub Copilot (model: GPT-6 Astra, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * test: enforce feature-assess trigger guards Assisted-by: GitHub Copilot (model: GPT-6 Astra, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update adrkit extension to v0.1.4 (#4600) Update adrkit extension submitted by @mbeacom: - extensions/catalog.community.json (version, download_url, compatibility range) - docs/community/extensions.md community extensions table (no row changes required) Closes #4571 Assisted-by: GitHub Copilot (model: gpt-5.2-codex, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update Azure Cosmos DB extension to v0.2.0 (#4602) Update cosmosdb extension submitted by @TheovanKraay:\n- extensions/catalog.community.json (version, download_url, and timestamps)\n- docs/community/extensions.md community extensions table (already current)\n\nCloses #4579\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\nAssisted-by: GitHub Copilot (model: gpt-5.2-codex, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Add OpenUP Governed Lifecycle extension to community catalog (#4598) Add openup extension submitted by @anvigo12 to the community catalog and documentation. Closes #4567. Assisted-by: GitHub Copilot (model: gpt-5.2-codex, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add OpenUP Governance preset to community catalog (#4596) Add openup-governance preset submitted by @anvigo12 to the community catalog and documentation table. Closes #4568 Assisted-by: GitHub Copilot (model: gpt-5.2-codex, autonomous) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com> Co-authored-by: Gyanu Mayank <gyanumayank0@gmail.com> Co-authored-by: temp-droid <82510451+temp-droid@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Ken Schlobohm <keschlob@microsoft.com>
Description
Fixes #4491.
BobIntegrationnever overrodebuild_exec_args(), so it inherited theIntegrationBaseno-op returningNone. Every workflowcommand:/prompt:step targeting Bob failed with "CLI not found or not installed" even with
bobon PATH. Bob Shell has a headless entry point (
bob run), so this dispatchesthrough it.
Also overrides
build_command_invocation(), which was inherited fromIntegrationBasewith a hardcoded.and rendered/speckit.specifywhereskills-mode projects install
.bob/skills/speckit-specify/. The class alreadycomputes the right separator in
effective_invoke_separator().requires_clistaysFalse— dispatch is opt-in by overriding the method,mirroring
CursorAgentIntegration. Same fix shape as #2631.Testing
uv run specify --helpuv sync && uv run pytestAdded 6 tests to
tests/integrations/test_integration_bob.py(62 pass in thatfile);
tests/test_agent_config_consistency.pypasses.Verified end-to-end against Bob Shell 2.0.1: a workspace skill at
.bob/skills/speckit-marker/was reached throughdispatch_command → build_exec_args → bob run, returningstatus: successwith one
UseSkillToolcall.Note: the full suite shows 11 failures in the bash/Python parity tests. They are
identical on
mainwithout this change — 11 failed / 7702 passed onmain,11 failed / 7708 passed here, same test set — and pass when run in isolation.
AI Disclosure
Investigation, patch and tests written with Claude; reviewed and verified by me.